Merge "rdbms: Group disconnect/reconnect errors by DB server name"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Fri, 27 Oct 2017 20:19:42 +0000 (20:19 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Fri, 27 Oct 2017 20:19:42 +0000 (20:19 +0000)
32 files changed:
.stylelintrc.json
Gruntfile.js
includes/ServiceWiring.php
includes/auth/CheckBlocksSecondaryAuthenticationProvider.php
includes/shell/Command.php
includes/shell/CommandFactory.php
includes/specials/SpecialUndelete.php
languages/i18n/fr.json
languages/i18n/hi.json
languages/i18n/hr.json
languages/i18n/kab.json
languages/i18n/ko.json
languages/i18n/sr-ec.json
package.json
resources/src/mediawiki.action/mediawiki.action.history.css
resources/src/mediawiki.legacy/commonPrint.css
resources/src/mediawiki.legacy/shared.css
resources/src/mediawiki.less/mediawiki.ui/mixins.less
resources/src/mediawiki.rcfilters/styles/mw.rcfilters.mixins.less
resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.ChangesListWrapperWidget.highlightCircles.seenunseen.less
resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.TagItemWidget.less
resources/src/mediawiki.skinning/content.externallinks.css
resources/src/mediawiki.skinning/content.parsoid.less
resources/src/mediawiki.skinning/elements.css
resources/src/mediawiki.special/mediawiki.special.comparepages.styles.less
resources/src/mediawiki.ui/components/checkbox.less
resources/src/mediawiki.ui/components/forms.less
resources/src/mediawiki.ui/components/inputs.less
resources/src/mediawiki.ui/components/radio.less
resources/src/mediawiki.widgets/mw.widgets.DateInputWidget.js
tests/phpunit/includes/shell/CommandFactoryTest.php
tests/phpunit/includes/shell/CommandTest.php

index 27e289d..60c8f36 100644 (file)
@@ -3,6 +3,6 @@
        "rules": {
                "no-descending-specificity": null,
 
-               "selector-no-id": null
+               "selector-max-id": null
        }
 }
index dbbfcb8..d1ef72f 100644 (file)
@@ -62,9 +62,6 @@ module.exports = function ( grunt ) {
                        installer: 'includes/installer/i18n/'
                },
                stylelint: {
-                       options: {
-                               syntax: 'less'
-                       },
                        src: '{resources/src,mw-config}/**/*.{css,less}'
                },
                watch: {
index 75ce8ec..0496b67 100644 (file)
@@ -442,6 +442,7 @@ return [
 
                $factory = new CommandFactory( $limits, $cgroup );
                $factory->setLogger( LoggerFactory::getInstance( 'exec' ) );
+               $factory->logStderr();
 
                return $factory;
        },
index f7a7ec1..7488fba 100644 (file)
@@ -77,9 +77,19 @@ class CheckBlocksSecondaryAuthenticationProvider extends AbstractSecondaryAuthen
        public function testUserForCreation( $user, $autocreate, array $options = [] ) {
                $block = $user->isBlockedFromCreateAccount();
                if ( $block ) {
+                       if ( $block->mReason ) {
+                               $reason = $block->mReason;
+                       } else {
+                               $msg = \Message::newFromKey( 'blockednoreason' );
+                               if ( !\RequestContext::getMain()->getUser()->isSafeToLoad() ) {
+                                       $msg->inContentLanguage();
+                               }
+                               $reason = $msg->text();
+                       }
+
                        $errorParams = [
                                $block->getTarget(),
-                               $block->mReason ?: \Message::newFromKey( 'blockednoreason' )->text(),
+                               $reason,
                                $block->getByName()
                        ];
 
index 1816c5a..9f080d5 100644 (file)
@@ -57,7 +57,10 @@ class Command {
        private $method;
 
        /** @var bool */
-       private $useStderr = false;
+       private $doIncludeStderr = false;
+
+       /** @var bool */
+       private $doLogStderr = false;
 
        /** @var bool */
        private $everExecuted = false;
@@ -180,7 +183,19 @@ class Command {
         * @return $this
         */
        public function includeStderr( $yesno = true ) {
-               $this->useStderr = $yesno;
+               $this->doIncludeStderr = $yesno;
+
+               return $this;
+       }
+
+       /**
+        * When enabled, text sent to stderr will be logged with a level of 'error'.
+        *
+        * @param bool $yesno
+        * @return $this
+        */
+       public function logStderr( $yesno = true ) {
+               $this->doLogStderr = $yesno;
 
                return $this;
        }
@@ -235,7 +250,7 @@ class Command {
                                $cmd = '/bin/bash ' . escapeshellarg( __DIR__ . '/limit.sh' ) . ' ' .
                                        escapeshellarg( $cmd ) . ' ' .
                                        escapeshellarg(
-                                               "MW_INCLUDE_STDERR=" . ( $this->useStderr ? '1' : '' ) . ';' .
+                                               "MW_INCLUDE_STDERR=" . ( $this->doIncludeStderr ? '1' : '' ) . ';' .
                                                "MW_CPU_LIMIT=$time; " .
                                                'MW_CGROUP=' . escapeshellarg( $this->cgroup ) . '; ' .
                                                "MW_MEM_LIMIT=$mem; " .
@@ -246,7 +261,7 @@ class Command {
                                $useLogPipe = true;
                        }
                }
-               if ( !$useLogPipe && $this->useStderr ) {
+               if ( !$useLogPipe && $this->doIncludeStderr ) {
                        $cmd .= ' 2>&1';
                }
 
@@ -424,6 +439,15 @@ class Command {
                        $this->logger->warning( "$logMsg: {command}", [ 'command' => $cmd ] );
                }
 
+               if ( $errBuffer && $this->doLogStderr ) {
+                       $this->logger->error( "Error running {command}: {error}", [
+                               'command' => $cmd,
+                               'error' => $errBuffer,
+                               'exitcode' => $retval,
+                               'exception' => new Exception( 'Shell error' ),
+                       ] );
+               }
+
                return new Result( $retval, $outBuffer, $errBuffer );
        }
 }
index c0b8f89..84dd50f 100644 (file)
@@ -37,6 +37,9 @@ class CommandFactory {
        /** @var string|bool */
        private $cgroup;
 
+       /** @var bool */
+       private $doLogStderr = false;
+
        /**
         * Constructor
         *
@@ -49,6 +52,16 @@ class CommandFactory {
                $this->setLogger( new NullLogger() );
        }
 
+       /**
+        * When enabled, text sent to stderr will be logged with a level of 'error'.
+        *
+        * @param bool $yesno
+        * @see Command::logStderr
+        */
+       public function logStderr( $yesno = true ) {
+               $this->doLogStderr = $yesno;
+       }
+
        /**
         * Instantiates a new Command
         *
@@ -60,6 +73,7 @@ class CommandFactory {
 
                return $command
                        ->limits( $this->limits )
-                       ->cgroup( $this->cgroup );
+                       ->cgroup( $this->cgroup )
+                       ->logStderr( $this->doLogStderr );
        }
 }
index 740207d..62a48c6 100644 (file)
@@ -969,7 +969,7 @@ class SpecialUndelete extends SpecialPage {
                        $key = urlencode( $row->fa_storage_key );
                        $pageLink = $this->getFileLink( $file, $this->getPageTitle(), $ts, $key );
                } else {
-                       $pageLink = $this->getLanguage()->userTimeAndDate( $ts, $user );
+                       $pageLink = htmlspecialchars( $this->getLanguage()->userTimeAndDate( $ts, $user ) );
                }
                $userLink = $this->getFileUser( $file );
                $data = $this->msg( 'widthheight' )->numParams( $row->fa_width, $row->fa_height )->text();
@@ -1049,7 +1049,7 @@ class SpecialUndelete extends SpecialPage {
                $time = $this->getLanguage()->userTimeAndDate( $ts, $user );
 
                if ( !$file->userCan( File::DELETED_FILE, $user ) ) {
-                       return '<span class="history-deleted">' . $time . '</span>';
+                       return '<span class="history-deleted">' . htmlspecialchars( $time ) . '</span>';
                }
 
                $link = $this->getLinkRenderer()->makeKnownLink(
index 202f247..3739450 100644 (file)
                        "Jona",
                        "Epok",
                        "DePlusJean",
-                       "Pierpao"
+                       "Pierpao",
+                       "Vexthedorito"
                ]
        },
        "tog-underline": "Soulignement des liens :",
index b2bd8fb..c74ede4 100644 (file)
        "recentchanges-legend": "हाल के परिवर्तन संबंधी विकल्प",
        "recentchanges-summary": "इस विकि पर हाल में हुए बदलाव इस पन्ने पर देखे जा सकते हैं।",
        "recentchanges-noresult": "इस अवधि के दौरान इन मापदंडों को पूर्ण करते कोई परिवर्तन नहीं किए गए हैं।",
+       "recentchanges-timeout": "इस खोज का समय समाप्त हो गया है आप विभिन्न खोज मापदंडों की कोशिश करना चाहेंगे।",
        "recentchanges-feed-description": "इस विकि पर हाल में हुए बदलाव इस फ़ीड में देखे जा सकते हैं।",
        "recentchanges-label-newpage": "इस संपादन से नया पृष्ठ बना",
        "recentchanges-label-minor": "यह एक छोटा सम्पादन है",
        "rcfilters-days-show-hours": "$1 {{PLURAL:$1|घंटा|घंटे}}",
        "rcfilters-highlighted-filters-list": "पर प्रकाश डाला:$1",
        "rcfilters-quickfilters": "सुरक्षित फ़िल्टर",
-       "rcfilters-quickfilters-placeholder-title": "à¤\95à¥\8bà¤\88 à¤\95ड़à¥\80 à¤\85भà¥\80 à¤¤à¤\95 à¤¸à¤¹à¥\87à¤\9cा à¤¨à¤¹à¥\80à¤\82 à¤\97या",
+       "rcfilters-quickfilters-placeholder-title": "à¤\95à¥\8bà¤\88 à¤«à¤¼à¤¿à¤²à¥\8dà¤\9fर à¤\85भà¥\80 à¤¤à¤\95 à¤¸à¤¹à¥\87à¤\9cà¥\87 à¤¨à¤¹à¥\80à¤\82 à¤\97à¤\8f",
        "rcfilters-quickfilters-placeholder-description": "अपने फ़िल्टर सेटिंग को सहेजने और बाद में उपयोग करने के लिए नीचे दिये बूकमार्क छवि पर क्लिक करें।",
        "rcfilters-savedqueries-defaultlabel": "सहेजे फ़िल्टर",
        "rcfilters-savedqueries-rename": "नाम बदलें",
        "rcfilters-filter-user-experience-level-unregistered-label": "अपंजीकृत",
        "rcfilters-filter-user-experience-level-unregistered-description": "संपादक जो लॉग-इन नहीं हैं।",
        "rcfilters-filter-user-experience-level-newcomer-label": "अपरिचित",
-       "rcfilters-filter-user-experience-level-newcomer-description": "4 दिनों की गतिविधि और 10 सम्पादन से कम वाले पंजीकृत संपादक।",
+       "rcfilters-filter-user-experience-level-newcomer-description": "पंजीकृत संपादकों, जिनके कम से कम 10 संपादन या 4 दिन की गतिविधि हो।",
        "rcfilters-filter-user-experience-level-learner-label": "शिक्षार्थियों",
        "rcfilters-filter-user-experience-level-learner-description": "पंजीकृत संपादक जिनका अनुभव \"नये संपादक\" और \"अनुभवी संपादक\" के बीच का है।",
        "rcfilters-filter-user-experience-level-experienced-label": "अनुभवी सदस्य",
        "rcfilters-view-namespaces-tooltip": "नाम स्थान द्वारा फिल्टर परिणाम",
        "rcfilters-view-tags-tooltip": "संपादन टैग का उपयोग करके फ़िल्टर परिणाम",
        "rcfilters-view-return-to-default-tooltip": "मुख्य फ़िल्टर मेनू पर लौटें",
+       "rcfilters-view-tags-help-icon-tooltip": "टैग किए गए संपादन के बारे में और जानें",
        "rcfilters-liveupdates-button": "जीवंत अद्यतन",
        "rcfilters-liveupdates-button-title-on": "जीवंत अद्यतन बंद करें",
        "rcfilters-liveupdates-button-title-off": "नये परिवर्तन प्रदर्शित करें जैसे ही वे घटित होते हैं",
        "ipb_blocked_as_range": "गलती: $1 यह आइपी सीधे बाधित नहीं है और अबाध्य नहीं किया जा सकता।\nफिर भी, $2 प्रकार को बाध्य किया जा सकता है, जिनको अबाध्य किया जा सकता है।",
        "ip_range_invalid": "गलत आईपी रेंज",
        "ip_range_toolarge": "/$1 से अधिक बड़े रेञ्ज ब्लॉकों की अनुमति नहीं है।",
+       "ip_range_exceeded": "आईपी श्रेणी इसकी अधिकतम सीमा से अधिक है अनुमत रेंज: / $1",
+       "ip_range_toolow": "आईपी रेंज प्रभावी रूप से अनुमति नहीं है",
        "proxyblocker": "प्रॉक्सी ब्लॉकर",
        "proxyblockreason": "आपका IP पता बाधित किया जा चुका है क्योंकि यह एक मुक्त प्रतिनिधि है।\nकृपया आप अपने इंटरनेट सेवा प्रदान करने वाले से या तकनीकी सहायक से सम्पर्क करें अथवा उन्हें इस भयावह सुरक्षा समस्या के बारे में सूचित करें।",
        "sorbsreason": "{{SITENAME}} द्वारा इस्तेमालमें लाये जाने वाले DNSBL में आपके आईपी एड्रेसको ओपन प्रॉक्सीमें दर्शाया गया हैं।",
index 547a2fd..29327c9 100644 (file)
        "statistics-files": "Postavljene datoteke",
        "statistics-edits": "Broj uređivanja od nastanka projekta {{SITENAME}}",
        "statistics-edits-average": "Prosječan broj uređivanja po stranici",
-       "statistics-users": "Prijavljeni [[Special:ListUsers|suradnici]]",
+       "statistics-users": "Registrirani [[Special:ListUsers|suradnici]]",
        "statistics-users-active": "Aktivni suradnici",
        "statistics-users-active-desc": "Suradnici koji su napravili neku od radnji u posljednjih {{PLURAL:$1|dan|$1 dana}}",
        "pageswithprop": "Stranice s određenim osobinama",
index e93cf04..089896b 100644 (file)
        "parser-template-recursion-depth-warning": "Talast n lqay n tiɣriwin n tilɣatin tefel ($1)",
        "language-converter-depth-warning": "Talast n lqay n uselkat n tutlayt tefel ($1)",
        "node-count-exceeded-category": "Isebtar anda amḍa n tikerwas yefel",
-       "node-count-exceeded-warning": "Asebter yefelen amḍan n tikerwas",
+       "node-count-exceeded-warning": "Asebter iɛedda amḍan afellay n tkerras",
        "expansion-depth-exceeded-category": "Isebtar anda lqay n uderrec yefel",
+       "expansion-depth-exceeded-category-desc": "Asebter iɛedda talqayt n temɣer tafellayt.",
        "expansion-depth-exceeded-warning": "Isebtar yefelen lqay n uderrec",
        "parser-unstrip-loop-warning": "Tifin n tineddict ur nezmer ara an sentuter",
        "parser-unstrip-recursion-limit": "Talast n usniles ur nezmer ara an sentuter tefel ($1)",
        "undo-success": "Tzemreḍ ad tessefsuḍ abeddil. Ssenqed asidmer akken ad tessneḍ ayen tebɣiḍ ad txdmeḍ d ṣṣeḥ, umbeɛd smekti ibeddlen u tkemmleḍ ad tessefsuḍ abeddil.",
        "undo-failure": "Ur yezmir ara ad issefu abeddel axaṭer yella amennuɣ abusari deg ubeddel.",
        "undo-norev": "Abeddel ur yezmer ara ad yetwekkes acku ulac-itt naɣ tetwekkes yakan",
+       "undo-nochange": "Ad yettban d akken abeddel yettwasefsex yakan.",
        "undo-summary": "Ssefsu tasiwelt $1 sɣur [[Special:Contributions/$2|$2]] ([[User talk:$2|Meslay]])",
        "undo-summary-username-hidden": "Semmewet tacaggart $1 sɣur amseqdac yeffren",
        "cantcreateaccount-text": "Asnulfu n umiḍan seg tansa IP (<b>$1</b>) tekyef sɣur [[User:$3|$3]].\n\nTaɣẓint n $3 : ''$2''",
        "page_last": "aneggaru",
        "histlegend": "Axtiri n umgerrad: rcem tankulin akken ad teẓreḍ imgerraden ger tisiwal u wekki ɣef enter/entrée neɣ ɣef taqeffalt deg ukessar.<br />\nTabadut: (tura) = amgirred akk d tasiwelt n tura,\n(amgirred) = amgirred akk d tasiwelt ssabeq, M = abeddel afessas.",
        "history-fieldset-title": "Nadi iceggiren",
-       "history-show-deleted": "Ekkes kan",
+       "history-show-deleted": "Aceggir yettwakksen kan",
        "histfirst": "tiqdimin",
        "histlast": "timaynutin",
        "historysize": "({{PLURAL:$1|1 atamḍan|$1 itamḍanen}})",
        "history-feed-description": "Amezruy n tsiwelt n usebter-agi deg wiki",
        "history-feed-item-nocomment": "$1 deg $2",
        "history-feed-empty": "Asebter i tebɣiḍ ulac-it.\nAhat yettumḥa neɣ yettbeddel isem-is.\nƐreḍ [[Special:Search|ad tnadiḍ deg wiki]] ɣef isebtar imaynuten.",
+       "history-edit-tags": "Ẓreg tirekkizin n ileqman yettwafernen",
        "rev-deleted-comment": "(agzul n taẓrigt yettwakes)",
        "rev-deleted-user": "(isem n wemseqdac yettwakes)",
-       "rev-deleted-event": "(asekcem yettwakkes)",
+       "rev-deleted-event": "(talqayt n umazray tettwakkes)",
        "rev-deleted-user-contribs": "[isem n useqdac naɣ tansa IP yetwemḥa - abeddel yeffer deg tiwsitin]",
        "rev-deleted-text-permission": "Lqem n usebter agi '''tetwesfeḍ'''.\nTilɣa llant deg [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} uɣmis n usfeḍ].",
        "rev-deleted-text-unhide": "Lqem n usebter agi '''tetwesfeḍ'''.\nTilɣa llant deg [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} uɣmis n usfeḍ].\nTzemreḍ meqqar [$1 ad ẓṛeḍ lqem agi]  ma tebɣiḍ",
index 3ba1eaf..4acbd83 100644 (file)
        "uploaded-script-svg": "업로드된 SVG 파일에서 스크립트로 만들 수 있는 \"$1\" 요소를 발견했습니다.",
        "uploaded-hostile-svg": "업로드된 SVG 파일의 스타일 요소에 안전하지 않은 CSS가 있습니다.",
        "uploaded-event-handler-on-svg": "이벤트 핸들러 속성 <code>$1=\"$2\"</code> 설정은 SVG 파일에서 사용할 수 없습니다.",
-       "uploaded-href-attribute-svg": "SVG 파일의 href 속성은 http:// 또는 https:// 대상의 링크만 허용되지만 <code>&lt;$1 $2=\"$3\"&gt;</code>를 발견했습니다.",
+       "uploaded-href-attribute-svg": "<a> 요소는 data: (내장 파일), http://, https://, 문서의 부분 (#, 동일 문서) 타겟만을 링크(href)할 수 있습니다. <image>와 같은 그 외 요소는 data:와 부분 타겟만 허용됩니다. SVG 파일을 내보낼 때 사진을 포함해 보세요. <code>&lt;$1 $2=\"$3\"&gt;</code>를 발견했습니다.",
        "uploaded-href-unsafe-target-svg": "안전하지 않은 데이터를 가리키는 href를 발견했습니다: 업로드된 SVG 파일의 URI 대상 <code>&lt;$1 $2=\"$3\"&gt;</code>",
        "uploaded-animate-svg": "업로드된 SVG 파일에서 \"from\" 특성 <code>&lt;$1 $2=\"$3\"&gt;</code>을 이용 중 \"animate\" 태그가 href를 변경할 수 있음을 발견했습니다.",
        "uploaded-setting-event-handler-svg": "이벤트 핸들러 속성을 차단으로 설정한 상태에서 <code>&lt;$1 $2=\"$3\"&gt;</code>가 업로드된 SVG 파일에서 발견되었습니다.",
index 7b99cf1..522b76a 100644 (file)
@@ -64,7 +64,7 @@
        "tog-shownumberswatching": "Прикажи број корисника који надгледају",
        "tog-oldsig": "Текући потпис:",
        "tog-fancysig": "Сматрај потпис као викитекст (без самоповезивања)",
-       "tog-uselivepreview": "Ð\9aоÑ\80иÑ\81Ñ\82и Ñ\82Ñ\80енÑ\83Ñ\82ни Ð¿Ñ\80еглед",
+       "tog-uselivepreview": "Ð\9fÑ\80икажи Ð¿Ñ\80еглед Ð±ÐµÐ· Ð¾Ñ\81вежаваÑ\9aа Ñ\81Ñ\82Ñ\80ане",
        "tog-forceeditsummary": "Упозори ме када не унесем опис измене",
        "tog-watchlisthideown": "Сакриј моје измене са списка надгледања",
        "tog-watchlisthidebots": "Сакриј измене ботова са списка надгледања",
index c30e150..8ff77d8 100644 (file)
@@ -26,8 +26,8 @@
     "karma-qunit": "1.2.1",
     "nodemw": "0.10.1",
     "qunitjs": "2.4.0",
-    "stylelint": "7.8.0",
-    "stylelint-config-wikimedia": "0.4.1",
+    "stylelint": "8.2.0",
+    "stylelint-config-wikimedia": "0.4.2",
     "wdio-junit-reporter": "0.2.0",
     "wdio-mocha-framework": "0.5.8",
     "wdio-sauce-service": "^0.3.1",
index f3ea163..520917a 100644 (file)
@@ -1,6 +1,6 @@
 /* Styles for the JavaScript enhancements of the history page */
 
-#pagehistory li.before input[name='oldid'],
-#pagehistory li.after input[name='diff'] {
+#pagehistory li.before input[ name='oldid' ],
+#pagehistory li.after input[ name='diff' ] {
        visibility: hidden;
 }
index 8ff0634..6931c7d 100644 (file)
@@ -77,8 +77,8 @@ a.stub {
 }
 
 /* Expand protocol-relative URLs for printing */
-.mw-body-content a.external.text[href^='//']:after,
-.mw-body-content a.external.autonumber[href^='//']:after {
+.mw-body-content a.external.text[ href^='//' ]:after,
+.mw-body-content a.external.autonumber[ href^='//' ]:after {
        content: ' (https:' attr( href ) ')';
 }
 
index 74233d6..ecdfb61 100644 (file)
@@ -56,36 +56,36 @@ wbr {
 
 /* Input types that should follow user direction, like buttons */
 /* TODO: What about buttons in wikipage content ? */
-input[type='submit'],
-input[type='button'],
-input[type='reset'],
-input[type='file'] {
+input[ type='submit' ],
+input[ type='button' ],
+input[ type='reset' ],
+input[ type='file' ] {
        direction: ltr;
 }
 
 /* Override default values */
-textarea[dir='ltr'],
-input[dir='ltr'] {
+textarea[ dir='ltr' ],
+input[ dir='ltr' ] {
        /* @noflip */
        direction: ltr;
 }
 
-textarea[dir='rtl'],
-input[dir='rtl'] {
+textarea[ dir='rtl' ],
+input[ dir='rtl' ] {
        /* @noflip */
        direction: rtl;
 }
 
 /* Default style for semantic tags */
-abbr[title],
-.explain[title] {
+abbr[ title ],
+.explain[ title ] {
        border-bottom: 1px dotted;
        cursor: help;
 }
 
 @supports ( text-decoration: underline dotted ) {
-       abbr[title],
-       .explain[title] {
+       abbr[ title ],
+       .explain[ title ] {
                border-bottom: 0;
                text-decoration: underline dotted;
        }
index 505aa61..1e078bd 100644 (file)
@@ -17,8 +17,8 @@
        line-height: normal;
        font-weight: normal;
 
-       & > input[type='checkbox'],
-       & > input[type='radio'] {
+       & > input[ type='checkbox' ],
+       & > input[ type='radio' ] {
                width: auto;
                height: auto;
                margin: 0 0.1em 0 0;
index f3d81b7..790e015 100644 (file)
@@ -55,9 +55,9 @@
 // work if the rules are inside the above widget LESS scope
 .highlight-changesListWrapperWidget( @bgcolor ) {
        .mw-rcfilters-ui-changesListWrapperWidget li&,
-               .mw-rcfilters-ui-changesListWrapperWidget & tr:first-child,
-               .mw-rcfilters-ui-changesListWrapperWidget tr&.mw-rcfilters-ui-changesListWrapperWidget-enhanced-toplevel:not(.mw-rcfilters-ui-changesListWrapperWidget-enhanced-grey) td:not( :nth-child( -n+2 ) ),
-               .mw-rcfilters-ui-changesListWrapperWidget tr&.mw-rcfilters-ui-changesListWrapperWidget-enhanced-nested:not(.mw-rcfilters-ui-changesListWrapperWidget-enhanced-grey) td:not( :nth-child( -n+4 ) ) {
+       .mw-rcfilters-ui-changesListWrapperWidget & tr:first-child,
+       .mw-rcfilters-ui-changesListWrapperWidget tr&.mw-rcfilters-ui-changesListWrapperWidget-enhanced-toplevel:not( .mw-rcfilters-ui-changesListWrapperWidget-enhanced-grey ) td:not( :nth-child( -n+2 ) ),
+       .mw-rcfilters-ui-changesListWrapperWidget tr&.mw-rcfilters-ui-changesListWrapperWidget-enhanced-nested:not( .mw-rcfilters-ui-changesListWrapperWidget-enhanced-grey ) td:not( :nth-child( -n+4 ) ) {
                background-color: @bgcolor;
        }
 }
index deaee28..5f6fbea 100644 (file)
@@ -21,7 +21,7 @@
                                                .mw-rcfilters-mixin-circle( @highlight-none, @result-circle-diameter, 0, true, @highlight-grey, true );
                                        }
 
-                                       .mw-rcfilters-ui-changesListWrapperWidget:not(.mw-rcfilters-ui-changesListWrapperWidget-highlighted) & {
+                                       .mw-rcfilters-ui-changesListWrapperWidget:not( .mw-rcfilters-ui-changesListWrapperWidget-highlighted ) & {
                                                .mw-rcfilters-mixin-circle( @highlight-none, @result-circle-diameter, 0, true, @highlight-bluedot, true );
                                        }
                                }
@@ -31,7 +31,7 @@
                                                .mw-rcfilters-mixin-circle( @highlight-grey, @result-circle-diameter, 0, true, @highlight-grey );
                                        }
 
-                                       .mw-rcfilters-ui-changesListWrapperWidget:not(.mw-rcfilters-ui-changesListWrapperWidget-highlighted) & {
+                                       .mw-rcfilters-ui-changesListWrapperWidget:not( .mw-rcfilters-ui-changesListWrapperWidget-highlighted ) & {
                                                .mw-rcfilters-mixin-circle( @highlight-bluedot, @result-circle-diameter, 0, true, @highlight-bluedot );
                                        }
                                }
index 0e7a635..e9c982a 100644 (file)
                        top: 50%;
                }
 
-               &[data-color='c1']:before {
+               &[ data-color='c1' ]:before {
                        .mw-rcfilters-mixin-circle( @highlight-c1, 10px, ~'-5px 0.5em 0 0' );
                }
 
-               &[data-color='c2']:before {
+               &[ data-color='c2' ]:before {
                        .mw-rcfilters-mixin-circle( @highlight-c2, 10px, ~'-5px 0.5em 0 0' );
                }
 
-               &[data-color='c3']:before {
+               &[ data-color='c3' ]:before {
                        .mw-rcfilters-mixin-circle( @highlight-c3, 10px, ~'-5px 0.5em 0 0' );
                }
 
-               &[data-color='c4']:before {
+               &[ data-color='c4' ]:before {
                        .mw-rcfilters-mixin-circle( @highlight-c4, 10px, ~'-5px 0.5em 0 0' );
                }
 
-               &[data-color='c5']:before {
+               &[ data-color='c5' ]:before {
                        .mw-rcfilters-mixin-circle( @highlight-c5, 10px, ~'-5px 0.5em 0 0' );
                }
        }
index cd674ef..2a64aa3 100644 (file)
@@ -19,7 +19,7 @@
        padding-right: 15px;
 }
 
-.mw-body-content a.external[href^='mailto:'],
+.mw-body-content a.external[ href^='mailto:' ],
 .link-mailto {
        background: url( images/mail.png ) center right no-repeat;
        /* @embed */
@@ -27,7 +27,7 @@
        padding-right: 15px;
 }
 
-.mw-body-content a.external[href^='ftp://'],
+.mw-body-content a.external[ href^='ftp://' ],
 .link-ftp {
        background: url( images/ftp-ltr.png ) center right no-repeat;
        /* @embed */
@@ -35,8 +35,8 @@
        padding-right: 15px;
 }
 
-.mw-body-content a.external[href^='irc://'],
-.mw-body-content a.external[href^='ircs://'],
+.mw-body-content a.external[ href^='irc://' ],
+.mw-body-content a.external[ href^='ircs://' ],
 .link-irc {
        background: url( images/chat-ltr.png ) center right no-repeat;
        /* @embed */
        padding-right: 15px;
 }
 
-.mw-body-content a.external[href$='.ogg'],
-.mw-body-content a.external[href$='.OGG'],
-.mw-body-content a.external[href$='.mid'],
-.mw-body-content a.external[href$='.MID'],
-.mw-body-content a.external[href$='.midi'],
-.mw-body-content a.external[href$='.MIDI'],
-.mw-body-content a.external[href$='.mp3'],
-.mw-body-content a.external[href$='.MP3'],
-.mw-body-content a.external[href$='.wav'],
-.mw-body-content a.external[href$='.WAV'],
-.mw-body-content a.external[href$='.wma'],
-.mw-body-content a.external[href$='.WMA'],
+.mw-body-content a.external[ href$='.ogg' ],
+.mw-body-content a.external[ href$='.OGG' ],
+.mw-body-content a.external[ href$='.mid' ],
+.mw-body-content a.external[ href$='.MID' ],
+.mw-body-content a.external[ href$='.midi' ],
+.mw-body-content a.external[ href$='.MIDI' ],
+.mw-body-content a.external[ href$='.mp3' ],
+.mw-body-content a.external[ href$='.MP3' ],
+.mw-body-content a.external[ href$='.wav' ],
+.mw-body-content a.external[ href$='.WAV' ],
+.mw-body-content a.external[ href$='.wma' ],
+.mw-body-content a.external[ href$='.WMA' ],
 .link-audio {
        background: url( images/audio-ltr.png ) center right no-repeat;
        /* @embed */
        padding-right: 15px;
 }
 
-.mw-body-content a.external[href$='.ogm'],
-.mw-body-content a.external[href$='.OGM'],
-.mw-body-content a.external[href$='.avi'],
-.mw-body-content a.external[href$='.AVI'],
-.mw-body-content a.external[href$='.mpeg'],
-.mw-body-content a.external[href$='.MPEG'],
-.mw-body-content a.external[href$='.mpg'],
-.mw-body-content a.external[href$='.MPG'],
+.mw-body-content a.external[ href$='.ogm' ],
+.mw-body-content a.external[ href$='.OGM' ],
+.mw-body-content a.external[ href$='.avi' ],
+.mw-body-content a.external[ href$='.AVI' ],
+.mw-body-content a.external[ href$='.mpeg' ],
+.mw-body-content a.external[ href$='.MPEG' ],
+.mw-body-content a.external[ href$='.mpg' ],
+.mw-body-content a.external[ href$='.MPG' ],
 .link-video {
        background: url( images/video.png ) center right no-repeat;
        /* @embed */
        padding-right: 15px;
 }
 
-.mw-body-content a.external[href$='.pdf'],
-.mw-body-content a.external[href$='.PDF'],
-.mw-body-content a.external[href*='.pdf#'],
-.mw-body-content a.external[href*='.PDF#'],
-.mw-body-content a.external[href*='.pdf?'],
-.mw-body-content a.external[href*='.PDF?'],
+.mw-body-content a.external[ href$='.pdf' ],
+.mw-body-content a.external[ href$='.PDF' ],
+.mw-body-content a.external[ href*='.pdf#' ],
+.mw-body-content a.external[ href*='.PDF#' ],
+.mw-body-content a.external[ href*='.pdf?' ],
+.mw-body-content a.external[ href*='.PDF?' ],
 .link-document {
        background: url( images/document-ltr.png ) center right no-repeat;
        /* @embed */
index 654b655..a36ba6c 100644 (file)
@@ -44,9 +44,9 @@ sub {
 /**
  * Block media items
  */
-figure[typeof*='mw:Image'],
-figure[typeof*='mw:Video'],
-figure[typeof*='mw:Audio'] {
+figure[ typeof*='mw:Image' ],
+figure[ typeof*='mw:Video' ],
+figure[ typeof*='mw:Audio' ] {
        margin: 0;
 
        a {
@@ -91,12 +91,12 @@ figure[typeof*='mw:Audio'] {
        }
 }
 
-figure[typeof~='mw:Image/Thumb'],
-figure[typeof~='mw:Video/Thumb'],
-figure[typeof~='mw:Audio/Thumb'],
-figure[typeof~='mw:Image/Frame'],
-figure[typeof~='mw:Video/Frame'],
-figure[typeof~='mw:Audio/Frame'] {
+figure[ typeof~='mw:Image/Thumb' ],
+figure[ typeof~='mw:Video/Thumb' ],
+figure[ typeof~='mw:Audio/Thumb' ],
+figure[ typeof~='mw:Image/Frame' ],
+figure[ typeof~='mw:Video/Frame' ],
+figure[ typeof~='mw:Audio/Frame' ] {
        display: table;
        text-align: center;
        border: 1px solid #c8ccd1;
@@ -139,9 +139,9 @@ figure[typeof~='mw:Audio/Frame'] {
        }
 }
 
-figure[typeof*='mw:Image/Thumb'],
-figure[typeof*='mw:Video/Thumb'],
-figure[typeof*='mw:Audio/Thumb'] {
+figure[ typeof*='mw:Image/Thumb' ],
+figure[ typeof*='mw:Video/Thumb' ],
+figure[ typeof*='mw:Audio/Thumb' ] {
        > a:after {
                content: '';
                width: 15px;
index 245fb53..366c5a9 100644 (file)
@@ -13,7 +13,7 @@ a {
        background: none;
 }
 
-a:not( [href] ) {
+a:not( [ href ] ) {
        cursor: pointer; /* Always cursor:pointer even without href */
 }
 
index c951169..87b7a8b 100644 (file)
@@ -10,7 +10,7 @@
        .box-sizing( border-box );
 }
 
-.mw-special-ComparePages .oo-ui-layout.oo-ui-panelLayout.oo-ui-panelLayout-padded.oo-ui-panelLayout-framed:nth-of-type(2) {
+.mw-special-ComparePages .oo-ui-layout.oo-ui-panelLayout.oo-ui-panelLayout-padded.oo-ui-panelLayout-framed:nth-of-type( 2 ) {
        margin-left: 2%;
 }
 
index c1626db..0c13daf 100644 (file)
@@ -49,7 +49,7 @@
                vertical-align: middle;
        }
 
-       [type='checkbox'] {
+       [ type='checkbox' ] {
                display: table-cell;
                position: relative;
                // Ensure the invisible input takes up the required `width` & `height`
index d3c76d0..0a9023e 100644 (file)
@@ -66,7 +66,7 @@
        }
 
        // Override input styling just for checkboxes and radio inputs.
-       input[type='radio'] {
+       input[ type='radio' ] {
                display: inline;
                .box-sizing( content-box );
                width: auto;
index 74dc0b7..1c79d52 100644 (file)
@@ -73,7 +73,7 @@
        }
 
        // Normalize styling for `<input type="search">`
-       &[type='search'] {
+       &[ type='search' ] {
                // Correct the odd appearance in Chrome and Safari 5
                -webkit-appearance: textfield;
 
@@ -103,7 +103,7 @@ textarea.mw-ui-input {
 // <button class="mw-ui-button mw-ui-progressive">Submit</button>
 //
 // Styleguide 1.2.
-input[type='number'],
+input[ type='number' ],
 .mw-ui-input-inline {
        display: inline-block;
        width: auto;
index 3d82e8e..d9b7c6d 100644 (file)
                vertical-align: middle;
        }
 
-       [type='radio'] {
+       [ type='radio' ] {
                // ensure the invisible radio takes up the required width
                width: @sizeInputBinary;
                height: @sizeInputBinary;
                // This is needed for Firefox mobile (See T73750 to workaround default Firefox stylesheet)
                max-width: none;
                margin: 0;
-               // Hide `input[type=radio]` and instead style the label that follows
+               // Hide `input[ type=radio ]` and instead style the label that follows
                // Support: VoiceOver. Use `opacity` so that VoiceOver can still identify the radio
                opacity: 0;
 
index f10c93d..9d2e93b 100644 (file)
                        format = llll.replace( lll.replace( ll, '' ), '' );
 
                        if ( this.longDisplayFormat ) {
-                               format = format.replace( 'MMM', 'MMMM' ).replace( 'ddd', 'dddd' );
+                               // Replace MMM to MMMM and ddd to dddd but don't change MMMM and dddd
+                               format = format.replace( /MMMM?/, 'MMMM' ).replace( /dddd?/, 'dddd' );
                        }
 
                        return format;
index aacfd43..f90e837 100644 (file)
@@ -23,11 +23,13 @@ class CommandFactoryTest extends PHPUnit_Framework_TestCase {
 
                $factory = new CommandFactory( $limits, $cgroup );
                $factory->setLogger( $logger );
+               $factory->logStderr();
                $command = $factory->create();
 
                $wrapper = TestingAccessWrapper::newFromObject( $command );
                $this->assertSame( $logger, $wrapper->logger );
                $this->assertSame( $cgroup, $wrapper->cgroup );
                $this->assertSame( $limits, $wrapper->limits );
+               $this->assertTrue( $wrapper->doLogStderr );
        }
 }
index 32d855e..81fae33 100644 (file)
@@ -118,4 +118,25 @@ class CommandTest extends PHPUnit_Framework_TestCase {
                        $this->assertEquals( 333333, strlen( $output ) );
                }
        }
+
+       public function testLogStderr() {
+               $this->requirePosix();
+
+               $logger = new TestLogger( true, function ( $message, $level, $context ) {
+                       return $level === Psr\Log\LogLevel::ERROR ? '1' : null;
+               }, true );
+               $command = new Command();
+               $command->setLogger( $logger );
+               $command->params( 'bash', '-c', 'echo ThisIsStderr 1>&2' );
+               $command->execute();
+               $this->assertEmpty( $logger->getBuffer() );
+
+               $command = new Command();
+               $command->setLogger( $logger );
+               $command->logStderr();
+               $command->params( 'bash', '-c', 'echo ThisIsStderr 1>&2' );
+               $command->execute();
+               $this->assertSame( 1, count( $logger->getBuffer() ) );
+               $this->assertSame( trim( $logger->getBuffer()[0][2]['error'] ), 'ThisIsStderr' );
+       }
 }